package com.miyu.system.utils.crawler.book;

import cn.hutool.core.util.StrUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.selector.Selectable;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析规则加返回数据处理
 * 字符元素处理 分割 拼接 替换  多个组合规则
 * 三段式处理 无@时默认取值 文本
 *
 * 三段处理 例如： class.test.@href  表示取class.test下的所有连接
 */
public class JXPageUtils {

    private static JXPageUtils invoke= new JXPageUtils();


    /**
     * 解析列表数据 返回Selectable
     * 一般处理列表数据使用
     * @param page
     * @param ruleStr
     * @return
     */
    static List<Selectable>  JXPageRuleByPage(Page page,String ruleStr){
        List<Selectable> nodes=null;
        String[] rtg = ruleStr.split("&");
        String [] num = rtg[0].split("\\.");
        if(num.length==3){
            //重组规则 //移除第一组最后一位
            ruleStr = num[0]+"."+num[1];
            for (int i=1;i<rtg.length;i++){
                ruleStr +="&"+rtg[i];
            }

            nodes  = page.getHtml().xpath(JXRleCommon(ruleStr)).nodes();
            //由于列表取值取值不一定从第一个开始 所以增加从指定位置开始
            if(nodes.size()>Integer.valueOf(num[2])){
                nodes = nodes.subList(Integer.valueOf(num[2]),nodes.size());
            }
        }else {
            nodes  = page.getHtml().xpath(JXRleCommon(ruleStr)).nodes();
        }
        return nodes;
    }

    /**
     * 正常解析数据 tg.sp(0@3)&lp(:@1)tg.rp(#nbsp@"")
     * 字符截取规则 tg.sp(0@2) 字符取substring(0,2)取值,
     * tg.lp(.@1) 指 split(".")分割取 第一个 & 符 合并取值 暂不做复杂处理 tg.sp()&lp() 格式
     * tg.rp(ces@ts) 指 replace('ce','ts')字符替换做指定字符替换
     * tg.lk(.@0)//由此包含 取连接地址
     * tg.sp(0@2) 字符取substring(0,2)取值
     * 规则说明  //[class='test']/p[1]|tg&lg(:)
     / * @param stable
     * @param ruleStr
     * @return
     */
    public static String JXPageRuleByTable(Selectable stable, String ruleStr) throws Exception {
        StringBuilder rs= new StringBuilder();
        if(StringUtils.isBlank(ruleStr)) {
            return rs.toString();
        }

        //分割拼接数据
        String[] rtg = ruleStr.split("#");
       String str =  JXRleCommon(rtg[0]);
       if(StrUtil.isBlank(str)){
           return "";
       }
        try{
     if(ruleStr.indexOf("@href")>0){
            rs = new StringBuilder(stable.xpath(str).links().get());
        }else if(ruleStr.toLowerCase().indexOf( "@all")>0){
         //数组转字符串
         rs = rs.append(stable.xpath(JXRleCommon(ruleStr)).nodes().toString().replaceAll("\\[|\\]|,", ""));
        }else{
            //获取连接根目录.links().get());
            Selectable xpath = stable.xpath(str);
            rs = new StringBuilder(String.valueOf(xpath));
        }
        } catch (Exception e) {
//            throw new RuntimeException(e);
            return "";
        }
        if(StrUtil.isBlank(rs.toString())){
            return rs.toString();
        }
        if(rtg.length>1){
            for (int i = 1; i < rtg.length; i++) {
                //附加规则解析 处理根据xpath取出的之再次进行处理
                //eg tg.rp()&tg.lg)|tg.rp()&tg.lg)
                //&和| 区别 可多个标签使用拼接使用 &一个字符规则组合取值 | 同一个字符按顺序处理
                String ps= rs.toString();
                /** 重置rs返回值*/
                rs = new StringBuilder();
                String [] s = rtg[i].split("&"); //
                for (int z=0;z<s.length;z++){
                    String method = s[z].substring(3,s[z].indexOf("("));
                    rs.append((String) invoke.getClass().getMethod(method, new Class[]{String.class, String.class}).invoke(invoke, new Object[]{s[z], ps}));
                }
            }
        }
        return rs.toString();
    }

    public static String  JXPageRuleByCheckRule(Page page,String ruleStr) throws Exception{
        String rs="";

        if(StringUtils.isBlank(ruleStr)) {
            return rs;
        }
        //如果ruleStr中包含href获取链接 使用links获取全链接
        if(ruleStr.toLowerCase().indexOf("@href")>0){
            rs = page.getHtml().xpath(JXRleCommon(ruleStr)).links().get();
        }else   if(ruleStr.toLowerCase().indexOf( "@all")>0){
            rs = page.getHtml().xpath(JXRleCommon(ruleStr)).nodes().toString();
        }else {
            rs = page.getHtml().xpath(JXRleCommon(ruleStr)).toString();
        }
        if(StringUtils.isBlank(rs)) {
            return rs;
        }
        String[] rtg = ruleStr.split("\\|");
        if(rtg.length>1){
            for (int i = 1; i < rtg.length; i++) {
                //附加规则解析 处理根据xpath取出的之再次进行处理
                //eg tg.rp()&tg.lg)|tg.rp()&tg.lg)
                //&和| 区别 可多个标签使用拼接使用 &一个字符规则组合取值 | 同一个字符按顺序处理
                String ps=rs;
                rs="";
                String [] s = rtg[i].split("&"); //
                for (int z=0;z<s.length;z++){
                    String mothod = s[z].substring(3,s[z].indexOf("("));
                    rs+=(String) invoke.getClass().getMethod(mothod,new Class[]{ String.class, String.class }).invoke(invoke,new Object[]{s[z],StringUtils.isNotBlank(ps)?ps:rs});
                }
            }
        }
        return rs;
    }

    /**
     * 公共解析规则 返回字符串
     * @param ruleSet
     * @return
     */
    @SneakyThrows
    public static String JXRleCommon(String ruleSet){

        //区分取值和附加条件对取值进行处理
        String[] arr = ruleSet.split("&");
        StringBuffer str = new StringBuffer();
        if(arr.length>0){
            for (int i = 0; i < arr.length; i++) {
                /* 分割段*/
                String [] s = arr[i].split("\\.");
                for (int j = 0; j < s.length; j++) {
                    //j=0  //只有标签 不做处理
                    if(j==1){
                        //当前标签就有取值
                        //tag.a@href
                        String [] m = s[j].split("@");
                        if(m.length>1){
                            if(s[0].equalsIgnoreCase("tag")){

                                str.append(i==0?"//":"/").append(m[0]);
                                if(m[1].equals("text")){
                                    str.append("/text()");
                                }else if(m[1].equalsIgnoreCase("href")|| m[1].equalsIgnoreCase("all")){
                                    //连接
                                }else{
                                    str.append("/@").append(m[1]);
                                }
                            }else{
                                str.append("//[ @").append(s[0]).append("='").append(m[0]).append("']");
                                if(m[1].equals("text")){
                                    str.append("/text()");
                                }else if(m[1].equalsIgnoreCase("href")|| m[1].equalsIgnoreCase("all")){
                                    //连接
                                }else{
                                    str.append("/@").append(m[1]);
                                }
                            }
                        }else{
                            if(s[0].equalsIgnoreCase("tag")){
                                str.append(i==0?"//":"/").append(s[1]);
                            }else{
                                str.append("//[ @").append(s[0]).append("='").append(s[1]).append("']");
                            }
                        }

                    }
                    if(j==2){
                        //取值类型
                        String [] m = s[j].split("@");
                        if(m.length>1){
                            str.append("[").append(m[0]).append("]");
                            if(m[1].equalsIgnoreCase("text")){
                                //文本
                                str.append("/text()");
                            }else
                            if(m[1].equalsIgnoreCase("href")|| m[1].equalsIgnoreCase("all")){
                                //连接类型
                            }else{
                                str.append("/@").append(m[1]);
                            }
                        }else{
                            str.append("[").append(m[0]).append("]");
                        }

                    }
                }

            }

        }


        return str.toString();
    }


    /**
     * tg.lp(.@1) 指分割 split(".")分割取 第一个 & 符
     * tg.rp(ces@ts) 指替换 replace('ce','ts')字符替换做指定字符替换
     * tg.lk(.@0)//由此包含 取连接地址
     * tg.sp(0@2) 指字符取 substring(0,2)取值
     * @param lp
     * @param st
     * @return
     */
    private static String  regex = "\\(([^}]*)\\)";//匹配小括号

    /**
     * 分割取值
     * @param str
     * @param obj
     * @return
     */
    public String lp (String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        String [] lpStr = obj.split(s[0]);
        if(lpStr.length>1) {
            rs = lpStr[Integer.parseInt(s[1])];
        }

        return rs;
    }

    /**
     * 截取取值
     * 第二个值不大于0 则从后取值
     * @param str
     * @param obj
     * @return
     */
    public String sp(String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        switch (s.length){
            case 1:
                //取后几位数据 同理第一为空 第二个为符
                rs = obj.substring(Integer.valueOf(s[0]),obj.length());
                break;
            case 2:
                if (StringUtils.isBlank(s[0])){
                    if(Integer.valueOf(s[1])<=0){
                        rs = obj.substring(obj.length()-Math.abs(Integer.valueOf(s[1])),obj.length());
                    }else {
                        rs = obj.substring(0,Math.abs(Integer.valueOf(s[1])));
                    }

                }else{
                    if(Integer.valueOf(s[1])>0) {
                        rs = obj.substring(Integer.valueOf(s[0]),Integer.valueOf(s[1]));
                    } else {
                        rs = obj.substring(Integer.valueOf(s[0]),obj.length()-Math.abs(Integer.valueOf(s[1])));
                    }
                }
                break;
            default:break;
        }
        return rs;
    }

    /**
     * 字符替换 $ 符替换空格 解决 替换文本中换行符<br>
     * @param str
     * @param obj
     * @return
     */
    public String rp(String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        if(s[0].indexOf("$")>-1)
            //rs = obj.replace(s[0].replace("$"," "),s[1].replace("$"," "));
        {
            rs = obj.replace(s[0].replace("$"," "),s[1].replace("$","&nbsp"));
        } else {
            rs = obj.replace(s[0],s[1]);
        }
        return rs;
    }


}